﻿using System.ConfigCenter.Server.DB;

using GCC.Container.Abstracts;

namespace System.ConfigCenter.Server.Models
{
    public class SystemConfigInfo
    {
        /// <summary>
        /// 配置主键ID
        /// </summary> 
        public long SCID { get; set; }
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; } = string.Empty;
        /// <summary>
        /// 值
        /// </summary>
        public string Value { get; set; } = string.Empty;
        /// <summary>
        /// 父级配置ID
        /// </summary>
        public long ParentSCID { get; set; }

        /// <summary>
        /// 类型枚举
        /// </summary> 
        public SystemConfigTypeEnum TypeEnum { get; set; }
        /// <summary>
        /// 子节点
        /// </summary>
        public List<SystemConfigInfo> Childs { get; set; } = new List<SystemConfigInfo>();

        /// <summary>
        /// 所有的配置缓存
        /// </summary>
        private static readonly List<SystemConfigInfo> _fullConfigTree = new();
        /// <summary>
        /// 所有的配置缓存
        /// </summary>
        private static readonly List<SystemConfig> _orignalConfigInfos = new();
        /// <summary>
        /// 日志对象
        /// </summary>
        private static AbsGCCLogger? _logger;

        /// <summary>
        /// 初始化整体配置
        /// 这里函数的代码并不追求性能极致,是因为从逻辑上来讲,配置项的个数应当被压制在400以内,否则系统明显会过于零碎,零碎意味着不稳定性的出现(当前项目并不是PaaS公有云以此为背景,不过度设计)
        /// 而400个Item的循环与遍历,是不追求所谓的性能的,下方代码是一个性能反例,但是这个反例不构成威胁,特此举例说明,当然可以优化掉,但是没有必要.
        /// </summary>
        public static void InitAllConfigData(AbsGCCLoggerProvider logger)
        {
            _logger = logger.CreateLogger<SystemConfigInfo>();
            if (GCCEntrance.DBManager is null || GCCEntrance.DBManager.GlobalReadDB is null)
            {
                _logger?.Error("db instance is null.");
                return;
            }
            var allConfigs = GCCEntrance.DBManager.GlobalReadDB.Select<SystemConfig>().ToList();

            var tempConfigs = new List<SystemConfigInfo>();
            allConfigs.Where(item => item.ParentSCID == 0).ToList().ForEach(item =>
            {
                var temp = new SystemConfigInfo()
                {
                    Name = item.Name,
                    ParentSCID = item.ParentSCID,
                    TypeEnum = item.TypeEnum,
                    Value = item.Value,
                    SCID = item.SCID
                };
                ConstructData(allConfigs, temp);
                tempConfigs.Add(temp);
            });
            ///这里这么写的原因有二,(不讨论循环,linq+循环是反例,只讨论写法),因为并行系统中,尽可能降低锁的范围是基本思考原则,虽然上方的代码很烂,但是整体是没有跑偏的,比如锁是当数据准备完毕后上锁.
            ///而只是清空,而不是变量指针重新赋值.


            lock (_fullConfigTree)
            {
                _fullConfigTree.Clear();
                _orignalConfigInfos.Clear();
                allConfigs.ForEach(item =>
                {
                    _orignalConfigInfos.Add(item);
                });
                tempConfigs.ForEach(item =>
                {
                    _fullConfigTree.Add(item);
                });
            }


        }

        private static void ConstructData(List<SystemConfig> allConfigs, SystemConfigInfo info)
        {
            allConfigs.Where(item => item.ParentSCID == info.SCID).ToList().ForEach(item =>
            {
                var temp = new SystemConfigInfo()
                {
                    Name = item.Name,
                    ParentSCID = item.ParentSCID,
                    TypeEnum = item.TypeEnum,
                    Value = item.Value,
                    SCID = item.SCID
                };
                info.Childs.Add(temp);
                ConstructData(allConfigs, temp);
            });
        }

        /// <summary>
        /// 根据路径获取数据
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string GetByPath(string[] path)
        {
            SystemConfigInfo? current = null;
            foreach (var pathItem in path)
            {
                if (current is null)
                {
                    current = _fullConfigTree.FirstOrDefault(item => item.Name.Equals(pathItem, StringComparison.OrdinalIgnoreCase));
                }
                else
                {
                    current = current.Childs.FirstOrDefault(item => item.Name.Equals(pathItem, StringComparison.OrdinalIgnoreCase));
                }
                if (current is null)
                {
                    return "";
                }
            }
            if (current is null)
            {
                return String.Empty;
            }

            return current.Value;
        }




    }
}
